Source code for qtealeaves.tooling.parameterized

# This code is part of qtealeaves.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""
The tooling to have parameterized models and instances.
"""
import typing

__all__ = ["_ParameterizedClass"]


[docs] class _ParameterizedClass: """ Abstract base class for any other class which needs to evaluate parameterization. """
[docs] def eval_param(self, elem, params): """ Evaluate a numeric, string, or typed parameter which might be defined via the parameter dictionary. While `eval_numeric_param` throws a key error if a string is not in the parameter dictionary, here strings (and types) are allowed as return values. **Arguments** elem : callable, string, int/float, list, or type Defines the parameter either via a function which return the value, a string being an entry in the parameter dictionary, or directly as the numeric value. params : dict The parameter dictionary, which will be passed to callables and used to evaluate string parameters. """ if isinstance(elem, list): # Parameters varying over sweeps would for example fall into this # if-case return [self.eval_param(subelem, params) for subelem in elem] if hasattr(elem, "__call__") and (not isinstance(elem, type)): # Classes implement the init apparently via call, so have to escape # via isinstace(..., type) val = elem(params) elif not isinstance(elem, typing.Hashable): # If it is not hashable, it cannot be an entry in the # dictionary, cannot be a string val = elem elif elem in params: val = params[elem] else: val = elem return val
[docs] def eval_numeric_param(self, elem, params): """ Evaluate a numeric parameter which might be defined via the parameter dictionary. **Arguments** elem : callable, string, or int/float Defines the parameter either via a function which return the value, a string being an entry in the parameter dictionary, or directly as the numeric value. params : dict The parameter dictionary, which will be passed to callables and used to evaluate string parameters. """ value = self.eval_param(elem, params) if isinstance(value, str | type): raise ValueError(f"Unable to resolve numeric parameters for {elem}.") return value
[docs] @staticmethod def eval_str_param(elem, params): """ Evaluate a string parameter. **Arguments** elem : callable, string, or int/float Defines the parameter either via a function which return the value, or directly as the numeric value. params : dict The parameter dictionary, which will be passed to callables. """ if hasattr(elem, "__call__"): val = elem(params) # pylint: disable-next=isinstance-second-argument-not-valid-type elif not isinstance(elem, typing.Hashable): # If it is not hashable, it cannot be an entry in the # dictionary val = elem elif elem in params: val = params[elem] else: val = elem return val
[docs] @staticmethod def eval_str_param_default(elem, params, default): """ Evaluate a string parameter and allow to set default. It sets the default as soon as elem is not callable. **Arguments** elem : callable, ... Defines the parameter via a callable. Any other variable will be overwritten by the default. params : dict The parameter dictionary passed to the callable. default : str The default value if elem is not callable. """ if hasattr(elem, "__call__"): val = elem(params) else: val = default return val
def _resolve_params_attr(self, params, attr_numeric=None, attr_str=None, idx=None): """ Resolve parameterized values (inplace-update). **Arguments** params : dict Parameter dictionary of the simulation which can be used to resolve the parameters. attr_numeric : list of strings or `None` For a list of strings, `getattr` and `setattr` is called for the the class to resolve potential parameterization with `eval_numeric_param` attr_str : list of strings or `None` For a list of strings, `getattr` and `setattr` is called for the the class to resolve potential parameterization with `eval_str_param` idx : int | None, optional Resolve and pick entry in list if value is a list. We take the last element if list is shorter than idx Default to `None` (no value in list is picked) """ if attr_numeric is not None: for elem in attr_numeric: value = getattr(self, elem) value = self.eval_numeric_param(value, params) if (idx is not None) and hasattr(value, "__len__"): # Take last element if list shorter than idx value = value[min(idx, len(value) - 1)] setattr(self, elem, value) if attr_str is not None: for elem in attr_str: value = getattr(self, elem) value = self.eval_str_param(value, params) if ( (idx is not None) and hasattr(value, "__len__") and (not isinstance(value, str)) ): value = value[idx] setattr(self, elem, value)